package com.lry;

import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 事务协调器
 */
@Slf4j
public class Tc {

    private Map<String,GlobalSession> map;

    public Tc(){
        this.map = new ConcurrentHashMap<>();
    }

    /**
     * 开启全局事务
     * 创建全局session，添加<xid,session>到 map
     * @return
     */
    public String globalBegin(Tm tm) {
        String xid = UUID.randomUUID().toString();
        GlobalSession globalSession = GlobalSession.createGlobalSession(xid,GlobalStatus.Begin,tm);
        map.put(xid,globalSession);
        log.info("tc向global_table表中插入数据");
        return xid;
    }

    /**
     *  全局事务回滚，删除global_table,删除lock_table释放全局锁，
     *  遍历当前全局事务的所有branch_table(并删除)的分支事务，通知RM回滚，
     *  RM收到后删除undo log, 并反向补偿
     * @param xid
     */
    public void globalRollback(String xid) {
        GlobalSession globalSession = assertGlobalSession(xid);
        log.info("tc删除global_table,删除lock_table释放全局锁");

        globalSession.setGlobalStatus(GlobalStatus.Rollbacking);
        for (BranchSession branchSession : globalSession.getBranchSessionList()) {
            branchSession.getRm().rollback(xid);
        }
    }

    /**
     * 全局事务提交，删除global_table, 删除lock_table释放全局锁，
     * 遍历当前全局事务的所有branch_table(并删除)的分支事务，通知RM，RM收到后删除undo log
     * @param xid
     */
    public void globalCommit(String xid) {
        GlobalSession globalSession = assertGlobalSession(xid);

        log.info("tc删除global_table,删除lock_table释放全局锁");

        globalSession.setGlobalStatus(GlobalStatus.Committing);
        for (BranchSession branchSession : globalSession.getBranchSessionList()) {
            branchSession.getRm().commit(xid);
        }

    }

    /**
     * 注册分支事务 向branch_table表中插入数据，向lock_table插入数据, 这一步可能会全局锁冲突
     * @param xid
     */
    public void branchRegister(String xid,Rm rm) {
        GlobalSession globalSession = assertGlobalSession(xid);
        log.info("tc向branch_table表中插入数据，向lock_table插入数据");

        BranchSession branchSession = BranchSession.createBranchSession(xid,BranchStatus.Registered,rm);
        globalSession.getBranchSessionList().add(branchSession);
    }



    public GlobalSession assertGlobalSession(String xid){
        GlobalSession globalSession = map.get(xid);
        if(null==globalSession){
            String error = "tc#assertGlobalSession globalSession is null";
            log.error(error);
            throw new RuntimeException(error);
        }
        return globalSession;
    }

    public void report(String xid,boolean commitResult) {
        if(!commitResult){
            GlobalSession globalSession = assertGlobalSession(xid);
            log.info("tc 收到一阶段上报结果为false");
            globalSession.setGlobalStatus(GlobalStatus.Rollbacking);
            for (BranchSession branchSession : globalSession.getBranchSessionList()) {
                branchSession.setStatus(BranchStatus.PhaseOne_Failed);
                branchSession.getRm().rollback(xid);
            }
        }
    }
}
